/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.web.core.jsploader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.*; import java.net.URLEncoder; import java.util.StringTokenizer; import java.util.Enumeration; import java.text.MessageFormat; import javax.servlet.ServletContext; import com.sun.jsp.Constants; import com.sun.jsp.JspException; import com.sun.jsp.compiler.Main; import com.sun.jsp.compiler.EscapeUnicodeWriter; import com.sun.jsp.compiler.Jsp1_0ParseEventListener; import com.sun.jsp.compiler.JspReader; import com.sun.jsp.compiler.ServletWriter; import com.sun.jsp.compiler.Parser; import org.openide.TopManager; import org.openide.NotifyDescriptor; import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; import org.openide.filesystems.LocalFileSystem; import org.openide.filesystems.FileSystemCapability; import org.openide.filesystems.FileUtil; import org.openide.filesystems.Repository; import org.openide.loaders.DataObject; import org.openide.compiler.Compiler; import org.openide.execution.NbClassPath; import org.openide.util.NbBundle; /** JSP compilation utilities * * @author Petr Jiricka */ public class JspCompileUtil { /** Generates a servlet from a JSP page in this thread. * @param fo JSP file to compile * @outputdir directory for the resulting servlet * @classfiledata classfiledata for the page * @isErrorPage <code>true</code> if this is an error page */ public static final void generate(JspReader reader, FileObject fo, String outputDir, Main.ClassFileData classfiledata, boolean isErrorPage) throws FileStateInvalidException, IOException, JspException { generate(reader, TopManager.getDefault().currentClassLoader(), new ServletContextImpl(fo.getFileSystem()), fo, classfiledata, outputDir, isErrorPage, getFileObjectFileName(getContextRoot(fo))); } public static void invalidateJspInRunningJasper(JspDataObject jspdo) { // pending } /** Finds a fileobject for an absolute file name or null if not found */ public static final FileObject findFileObjectForFile(String fileName) { String canName = ""; // NOI18N String canName2 = ""; // NOI18N try { canName = new File(fileName).getCanonicalPath(); } catch (IOException e) { return null; } String resFriendly = canName.replace(File.separatorChar, '/'); Repository rep = TopManager.getDefault().getRepository(); int sepFound = -1; while (true) { sepFound = resFriendly.indexOf('/', sepFound + 1); if (sepFound == -1) return null; String resName = resFriendly.substring(sepFound); FileObject fo = rep.findResource(resName); if (fo == null) continue; File ff = NbClassPath.toFile(fo); if (ff == null) continue; // verify that they're the same try { canName2 = ff.getCanonicalPath(); } catch (IOException e) { continue; } if (!(canName2.equals(canName))) continue; return fo; } } /** Returns true if the dir exists when we finish */ private static boolean myMkdirs(File f) { if (f.exists()) return true; if (!f.isAbsolute()) f = f.getAbsoluteFile(); String par = f.getParent(); if (par == null) return false; if (!myMkdirs(new File(par))) return false; f.mkdir(); return f.exists(); } public static String getClassNameSansNumberSansPackage(FileObject jspObj) throws FileStateInvalidException { String jspFile = getFileObjectFileName(jspObj); File jsp = new File(jspFile); String pkgName = Main.getPackageName(jsp); ServletContext context = new ServletContextImpl(jspObj.getFileSystem()); String prefix = Main.getPrefix(jsp.getPath(), context.getRealPath("")); return prefix + Main.getBaseClassName(jsp) + "_jsp_"; } public static final String getFileObjectFileName(FileObject fo) throws FileStateInvalidException { File ff = NbClassPath.toFile(fo); if (ff == null) throw new FileStateInvalidException(NbBundle.getBundle(JspCompileUtil.class).getString("CTL_NotLocalFile")); return ff.getAbsolutePath(); } // @deprecated context root is always the filesystem root /** Gets the folder which is at the root of the context into which fo belongs */ public static final FileObject getContextRoot(FileObject fo) throws FileStateInvalidException { // pending return fo.getFileSystem().getRoot(); } /** Gets the folder which is the root output folder for the context into which fo belongs */ public static final FileObject getContextOutputRoot(FileObject fo) throws IOException { File serverRoot = getOutputRootFolder(); FileSystem fs = fo.getFileSystem(); File contextRoot = new File(serverRoot, URLEncoder.encode(fs.getSystemName())); return getAsRootOfFileSystem(contextRoot); } /** Gets the root OUTPUT folder for all contexts in NB systm FileSystem. */ private static File getOutputRootFolder() { String path = System.getProperty("netbeans.user"); if (path == null || path.length() == 0) { FileObject sysRoot = TopManager.getDefault().getRepository().getDefaultFileSystem().getRoot(); path = NbClassPath.toFile(sysRoot).getAbsoluteFile().getParent(); if (path == null) throw new InternalError(); } if (!path.endsWith(File.separator)) path = path + File.separator; path = path + "temp" + File.separator + "jspwork"; // NOI18N File myRoot = (new File(path)).getAbsoluteFile(); return myRoot; } /** Does the following: * <ul> * <li>creates a hidden LocalFileSystem (with compile, execute and debug capabilities) * with root in <code>intendedRoot</code>, if it does not exist yet</li> * <li>returns the root of this filesystem * </ul> */ private static FileObject getAsRootOfFileSystem(File intendedRoot) { // try to find it among current filesystems for (Enumeration en = TopManager.getDefault().getRepository().getFileSystems(); en.hasMoreElements(); ) { FileSystem fs = (FileSystem)en.nextElement(); File root = NbClassPath.toFile(fs.getRoot()); if (root != null) { if (root.equals(intendedRoot)) return fs.getRoot(); } } // does not exist in repository if (!intendedRoot.exists()) { boolean success = myMkdirs(intendedRoot); } FileSystemCapability.Bean cap = new FileSystemCapability.Bean(); cap.setCompile(true); cap.setExecute(true); cap.setDebug(true); cap.setDoc(false); LocalFileSystem newFs = new LocalFileSystem(cap); try { newFs.setRootDirectory(intendedRoot); } catch (Exception e) { NotifyDescriptor.Message message = new NotifyDescriptor.Message( MessageFormat.format(NbBundle.getBundle(JspCompileUtil.class). getString("EXC_JspFSNotCreated"), new Object[] {intendedRoot.getAbsolutePath()}), NotifyDescriptor.ERROR_MESSAGE); TopManager.getDefault().notify(message); return null; } newFs.setHidden(true); TopManager.getDefault().getRepository().addFileSystem(newFs); return newFs.getRoot(); } /** Returns an absolute context URL (starting with '/') for a relative URL and base URL. * @param relativeTo url to which the relative URL is related. Treated as directory iff * ends with '/' * @param url the relative URL by RFC 2396 * @exception IllegalArgumentException if url is not absolute and relativeTo * can not be related to, or if url is intended to be a directory */ public static String resolveRelativeURL(String relativeTo, String url) { String result; if (url.startsWith("/")) { // NOI18N result = "/"; // NOI18N url = url.substring(1); } else { // canonize relativeTo if (!relativeTo.startsWith("/")) // NOI18N throw new IllegalArgumentException(); relativeTo = resolveRelativeURL(null, relativeTo); int lastSlash = relativeTo.lastIndexOf('/'); if (lastSlash == -1) throw new IllegalArgumentException(); result = relativeTo.substring(0, lastSlash + 1); } // now url does not start with '/' and result starts with '/' and ends with '/' StringTokenizer st = new StringTokenizer(url, "/", true); // NOI18N while(st.hasMoreTokens()) { String tok = st.nextToken(); //System.out.println("token : \"" + tok + "\""); // NOI18N if (tok.equals("/")) { // NOI18N if (!result.endsWith("/")) // NOI18N result = result + "/"; // NOI18N } else if (tok.equals("")) // NOI18N ; // do nohing else if (tok.equals(".")) // NOI18N ; // do nohing else if (tok.equals("..")) { // NOI18N String withoutSlash = result.substring(0, result.length() - 1); int ls = withoutSlash.lastIndexOf("/"); // NOI18N if (ls != -1) result = withoutSlash.substring(0, ls + 1); } else { // some file result = result + tok; } //System.out.println("result : " + result); // NOI18N } return result; } /** Returns a FileObject whose URL is relative to a given fileObject. Doesn't allow to backtrack any * higher in the hierarchy than <code>rootFile</code>. Returns <code>null</code> if fileobject not found. * @param relativeTo FileObject relative to which the URL shoud be resolved. May be null if url is absolute * @param url URL to resolve. May start with a '/', in such a case <code>relativeTo</code> param is ignored * @param rootFile root of the hierarchy. <br> * Pending: if <code>null</code>, the repository root should be the root. */ public static FileObject resolveRelativeURL(FileObject relativeTo, String url, FileObject rootFile) { if (rootFile == null) //pending throw new IllegalArgumentException(); else { // find the origin FileObject origin; if (url.startsWith("/")) { // NOI18N origin = rootFile; } else { if (relativeTo == null) return null; origin = relativeTo.isFolder() ? relativeTo : relativeTo.getParent(); } // now process the URL StringTokenizer st = new StringTokenizer(url, "/"); // NOI18N while(st.hasMoreTokens()) { String tok = st.nextToken(); if (tok.equals("")) // NOI18N ; // do nohing else if (tok.equals(".")) // NOI18N ; // do nohing if (tok.equals("..")) { // NOI18N if (!rootFile.equals(origin)) origin = origin.getParent(); } else { // some file FileObject newFile = origin.getFileObject(tok); if (newFile == null) { int lastDot = tok.lastIndexOf('.'); if (lastDot == -1) return null; newFile = origin.getFileObject(tok.substring(0, lastDot), tok.substring(lastDot + 1)); if (newFile == null) return null; origin = newFile; } } } return origin; } } /** Generates servlet source from a JSP. * @param reader reader form which to read the JSP * @param classloader classloader for loading beans * @param context servletcontext * @param s file name of the source JSP * @param classfiledata classfiledata for the JSP * @param outputDir output directory * @param isErrorPage whether this is an error page * @param s2 don't know */ public static final void generate(JspReader reader, ClassLoader classloader, ServletContext context, FileObject jspObj, Main.ClassFileData classfiledata, String outputDir, boolean isErrorPage, String s2) throws JspException, IOException { String s = getFileObjectFileName(jspObj); File file = new File(s); file.getPath(); String s3 = Main.getPackageName(file); String s4 = getClassNameSansNumberSansPackage(jspObj) + classfiledata.getNumber(); // NOI18N String servletName = Main.getJavaFileName(s4, outputDir); File servletDir = new File(servletName).getAbsoluteFile().getParentFile(); myMkdirs(servletDir); ServletWriter servletwriter = new ServletWriter(new PrintWriter( new EscapeUnicodeWriter(new FileOutputStream(servletName)))); try { Jsp1_0ParseEventListener jsp1_0parseeventlistener = instantiateJsp1_0ParseEventListener( context, classloader, reader, servletwriter, s, s4, s3, isErrorPage, s2, outputDir); Parser parser = new Parser(reader, jsp1_0parseeventlistener); jsp1_0parseeventlistener.beginPageProcessing(); parser.parse(); jsp1_0parseeventlistener.endPageProcessing(); } finally { servletwriter.close(); } } public static JspInfo analyzePage(JspReader reader, FileObject jsp) throws JspException, FileStateInvalidException { AnalyzerParseEventListener listener = new AnalyzerParseEventListener(reader, jsp.getPackageNameExt('/', '.'), new ServletContextImpl(jsp.getFileSystem())); Parser parser = new Parser(reader, listener); listener.beginPageProcessing(); parser.parse(); listener.endPageProcessing(); return listener.getJspInfo(); } /** Renames the resulting class. * @param jspFile JSP file object * @param classfiledata classfiledata for the JSP * @param outputDir output directory * @exception JspException if the file could not be renamed * @return true if the file to be renamed existed */ public static final boolean renameClass(FileObject jspFile, Main.ClassFileData classfiledata, String outputDir) throws JspException, IOException { File file = new File(getFileObjectFileName(jspFile)); file.getPath(); String s4 = getClassNameSansNumberSansPackage(jspFile) + classfiledata.getNumber(); // NOI18N String s8 = outputDir + File.separatorChar; s8 = s8 + s4 + ".class"; // NOI18N File file2 = new File(s8); // check that the class file exists if (!file2.exists()) return false; File file3 = new File(classfiledata.getClassFileName()); if (file3.exists()) { file3.delete(); } if (!file2.renameTo(file3)) { throw new JspException(java.text.MessageFormat.format( org.openide.util.NbBundle.getBundle(JspCompileUtil.class).getString("CTL_NotRenamed"), new Object[] {file2, file3})); } else return true; } /*public static final void compileSource(String s, Main.ClassFileData classfiledata, String outputDir, boolean keepGenerated) throws JspException, IOException { // pending - may be wrong File file = new File(s); file.getPath(); String s3 = Main.getPackageName(file); String s4 = Main.getBaseClassName(file) + "_jsp_" + classfiledata.getNumber(); String s5 = Main.getJavaFileName(s4, outputDir); ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(256); sun.tools.javac.Main main1 = new sun.tools.javac.Main(bytearrayoutputstream, "javac"); String s6 = System.getProperty("path.separator"); String as[] = { s5, "-classpath", System.getProperty("java.class.path") + s6 + System.getProperty("jsp.class.path", ".") + s6 + outputDir, "-d", outputDir }; boolean flag2 = main1.compile(as); if(!keepGenerated) { File file1 = new File(s5); file1.delete(); } if(!flag2) { String s7 = bytearrayoutputstream.toString(); throw new JspException("Compilation failed:" + s7); } String s8 = outputDir + File.separatorChar; if (s3 != null && !s3.equals("")) s8 = s8 + s3.replace('.', File.separatorChar) + File.separatorChar; s8 = s8 + s4 + ".class"; File file2 = new File(s8); File file3 = new File(classfiledata.getClassFileName()); if (file3.exists()) file3.delete(); if (!file2.renameTo(file3)) throw new JspException("Unable to rename class file " + file2 + " to " + file3); else return; }*/ private static Jsp1_0ParseEventListener instantiateJsp1_0ParseEventListener( ServletContext context, ClassLoader classloader, JspReader jspreader, ServletWriter servletwriter, String s, String s4, String s3, boolean isErrorPage, String s2, String outputDir) { try { Constructor evListConst = Jsp1_0ParseEventListener.class.getDeclaredConstructor(new Class[] { ServletContext.class, ClassLoader.class, JspReader.class, ServletWriter.class, String.class, String.class, String.class, Boolean.TYPE, String.class, String.class}); evListConst.setAccessible(true); return (Jsp1_0ParseEventListener)evListConst.newInstance(new Object[] { context, classloader, jspreader, servletwriter, s, s4, s3, new Boolean(isErrorPage), s2, outputDir}); } catch (NoSuchMethodException e) { throw new InternalError(); } catch (SecurityException e) { throw new InternalError(); } catch (ClassCastException e) { throw new InternalError(); } catch (IllegalAccessException e) { throw new InternalError(); } catch (InvocationTargetException e) { throw new InternalError(); } catch (InstantiationException e) { throw new InternalError(); } } /** Clones a Main.ClassFileData object */ public static Main.ClassFileData cloneClassFileData(Main.ClassFileData toClone) { return new Main.ClassFileData(toClone.isOutDated(), toClone.getClassFileName(), toClone.getClassName()); } /* public static final void compile(ClassLoader classloader, ServletContext context, String s, Main.ClassFileData classfiledata, String outputDir, boolean keepGenerated, boolean isErrorPage, String s2) throws JspException, IOException { File file = new File(s); file.getPath(); String s3 = Main.getPackageName(file); String s4 = Main.getBaseClassName(file) + "_jsp_" + classfiledata.getNumber(); String s5 = Main.getJavaFileName(s4, outputDir); JspReader jspreader = JspReader.createJspReader(s); ServletWriter servletwriter = new ServletWriter(new PrintWriter(new EscapeUnicodeWriter(new FileOutputStream(s5)))); Jsp1_0ParseEventListener jsp1_0parseeventlistener = new Jsp1_0ParseEventListener2(context, classloader, jspreader, servletwriter, s, s4, s3, isErrorPage, s2, outputDir); Parser parser = new Parser(jspreader, jsp1_0parseeventlistener); jsp1_0parseeventlistener.beginPageProcessing(); parser.parse(); jsp1_0parseeventlistener.endPageProcessing(); servletwriter.close(); ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(256); sun.tools.javac.Main main1 = new sun.tools.javac.Main(bytearrayoutputstream, "javac"); String s6 = System.getProperty("path.separator"); String as[] = { s5, "-classpath", System.getProperty("java.class.path") + s6 + System.getProperty("jsp.class.path", ".") + s6 + outputDir, "-d", outputDir }; boolean flag2 = main1.compile(as); if(!keepGenerated) { File file1 = new File(s5); file1.delete(); } if(!flag2) { String s7 = bytearrayoutputstream.toString(); throw new JspException("Compilation failed:" + s7); } String s8 = outputDir + File.separatorChar; if (s3 != null && !s3.equals("")) s8 = s8 + s3.replace('.', File.separatorChar) + File.separatorChar; s8 = s8 + s4 + ".class"; File file2 = new File(s8); File file3 = new File(classfiledata.getClassFileName()); if (file3.exists()) file3.delete(); if (!file2.renameTo(file3)) throw new JspException("Unable to rename class file " + file2 + " to " + file3); else return; }*/ } /* * Log * 19 Gandalf 1.18 1/27/00 Petr Jiricka Changes in generating * names of the servlet * 18 Gandalf 1.17 1/13/00 Petr Jiricka More i18n * 17 Gandalf 1.16 1/12/00 Petr Jiricka Fully I18n-ed * 16 Gandalf 1.15 1/12/00 Petr Jiricka i18n phase 1 * 15 Gandalf 1.14 1/10/00 Petr Jiricka Significant compilation * change - prepare compilers for Java beforehand. * 14 Gandalf 1.13 1/7/00 Petr Jiricka Safe File.mkdirs() used * 13 Gandalf 1.12 1/6/00 Petr Jiricka Cleanup * 12 Gandalf 1.11 1/4/00 Petr Jiricka * 11 Gandalf 1.10 1/3/00 Petr Jiricka Always close the writer. * 10 Gandalf 1.9 12/28/99 Petr Jiricka getContextRoot * un-deprecated * 9 Gandalf 1.8 12/20/99 Petr Jiricka Checking in changes made * in the U.S. * 8 Gandalf 1.7 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 7 Gandalf 1.6 10/12/99 Petr Jiricka Removed debug messages * 6 Gandalf 1.5 10/10/99 Petr Jiricka Changes relaetd to * servlet package move * 5 Gandalf 1.4 10/10/99 Petr Jiricka outputDir does not throw * an exception * 4 Gandalf 1.3 9/29/99 Petr Jiricka cloneClassFileData() * utility method * 3 Gandalf 1.2 9/27/99 Petr Jiricka * 2 Gandalf 1.1 9/22/99 Petr Jiricka Added File -> FileObject * conversion * 1 Gandalf 1.0 9/22/99 Petr Jiricka * $ */